package com.lerays.spider.sougou.hack;

import java.io.IOException;

import org.apache.http.Header;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.CloseableHttpClient;

/**
 * yat, This is the very key point
 * 	mean a single web wechat client session and with
 * it we could access the history and the other api that need to be authorized
 * 
 * @author	chenxin<chenxin619315@gmail.com>
 * @version 2015.06.15
 */
public class Session 
{
	/**
	 * username
	*/
	private String username = null;
	
	/**
	 * referer page url 
	*/
	private String refererUrl = null;
	
	/**
	 * intermediate page url to lead to the real history page
	 * 	that could access the a specifield biz history data published 
	 * 
	 * {biz}: urlencode biz
	*/
	private String checkUrl = null;
	
	/**
	 * sync check url
	 * to fetch the incoming fresh message i guess  
	*/
	private String syncUrl = null;
	
	/**
	 * session access cookies
	 * demo: webwxuvid=30e8b2ba139a515fae8f957713e0fc91318575401ec7492ee26c55b34d42d14ec1676d4caa32af3fc2e384cd4b33a79e; ptui_loginuin=1187582057; ptcz=41847f8499ed9383cef88b1c23e91b369377a29e4c244fbb8ffa1c33d03bd797; pt2gguin=o1187582057; pgv_pvi=190392320; pgv_si=s9218027520; mm_lang=en_US; wxstaytime=1434357686; wxloadtime=1434357686_expired; wxpluginkey=1434329836; wxuin=798216536; wxsid=K8LK6Bnma5v6YChw; webwx_data_ticket=AQbsknsW69fNJ+frajcJJDUe 
	*/
	private String cookies = null;
	
	/**
	 * session data conmunication thread 
	*/
	private Thread thread = null;
	private HttpGet request = null;
	private String userAgent = null;
	
	private volatile boolean validate = true;
	private int failCount = 0;
	
	/**
	 * construct method to create a new session client 
	 * 
	 * @param	username
	 * @param	deviceId
	 * @param	sKey
	 * @param	cookies
	 * @param	syncCheckUrl
	*/
	public Session( 
			String username, String refererUrl, String checkUrl, 
			String cookies, String syncUrl, String userAgent )
	{
		this.username = username;
		this.refererUrl = refererUrl;
		this.checkUrl = checkUrl;
		this.cookies = cookies;
		this.syncUrl = syncUrl;
		this.userAgent = userAgent;
	}
	
	/**
	 * start the current session 
	 * 
	 * @param	httpClient
	 * @return	Session
	*/
	public Session start( final CloseableHttpClient httpClient )
	{
		if ( syncUrl == null ) throw new NullPointerException();
		if ( httpClient == null ) throw new NullPointerException();
		
		if ( thread != null )
		{
			return this;
		}
		
		request = new HttpGet(syncUrl);
		request.setHeader("User-Agent", userAgent);
		request.setHeader("Referer", refererUrl);
		request.setHeader("Cookie", cookies);
		
		thread = new Thread(new Runnable(){
			@Override
			public void run() 
			{
				while ( true )
				{
					if ( validate == false )
					{
						break;
					}
					
					try {
						CloseableHttpResponse response = httpClient.execute(request);
						String content = org.apache.commons.io.IOUtils.toString(response.getEntity().getContent(), "utf-8");
						//may coming return content
						//window.synccheck={retcode:"0",selector:"0"}
						//System.out.println("syncheck{"+username+"}: {"+content.replaceAll("\\s{2,}", " ")+"}");
						
						response.close();
						response = null;
					} catch (ClientProtocolException e) {
						e.printStackTrace();
					} catch (IOException e) {
						e.printStackTrace();
					}
					
					try {
						Thread.sleep(5000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		});
		thread.start();
		
		return this;
	}
	
	/**
	 * create and return the final intermediate page url to access the biz history page 
	 * 
	 * @param	httpClient
	 * @param	biz
	 * @return	String
	*/
	public String getAccessUrl( CloseableHttpClient httpClient, String biz ) 
	{
		String interUrl = checkUrl.replace("{biz}", biz);
		
		/*
		 * access the intermediate url to fecth the final history access url 
		*/
		request = new HttpGet(interUrl);
		request.setHeader("User-Agent", userAgent);
		request.setHeader("Referer", refererUrl);
		request.setHeader("Cookie", cookies);
		
		HttpClientContext context = HttpClientContext.create();
		CloseableHttpResponse response;
		String accessUrl = null;
		
		try {
			response = httpClient.execute(request, context);
			//String content = org.apache.commons.io.IOUtils.toString(response.getEntity().getContent(), "utf-8");
			//System.out.println("urlfetch: "+content);
			
			/*
			 * when the current session canot return the access url
			 * 	we consider something bad happen to it and we will disable it, 
			 * so the session factory will remove it 
			*/
			Header locationHeader = response.getFirstHeader("Location");
			if ( locationHeader == null )
			{
				if ( failCount++ > 3 )
				{
					validate = false;		//disable it
				}
			}
			else
			{
				accessUrl = response.getFirstHeader("Location").getValue();
				int anchorIdx = accessUrl.indexOf('#');
				if ( anchorIdx > -1 )
				{
					accessUrl = accessUrl.substring(0, anchorIdx);
				}
				accessUrl += "&f=json";		//append the format arguments
			}
			
			//System.out.println(accessUrl);
			response.close();
			response = null;
		} 
		catch (IOException e) 
		{
			if ( failCount++ > 3 ) 
			{
				validate = false;
			}
		}
		
		return accessUrl;
	}
	
	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}
	
	public String getRefererUrl() {
		return refererUrl;
	}

	public void setRefererUrl(String refererUrl) {
		this.refererUrl = refererUrl;
	}

	public String getCheckUrl() {
		return checkUrl;
	}

	public void setCheckUrl(String checkUrl) {
		this.checkUrl = checkUrl;
	}

	public String getSyncUrl() {
		return syncUrl;
	}

	public void setSyncUrl(String syncUrl) {
		this.syncUrl = syncUrl;
	}

	public String getCookies() {
		return cookies;
	}

	public void setCookies(String cookies) {
		this.cookies = cookies;
	}

	public Thread getThread() {
		return thread;
	}

	public void setThread(Thread thread) {
		this.thread = thread;
	}

	public String getUserAgent() {
		return userAgent;
	}

	public void setUserAgent(String userAgent) {
		this.userAgent = userAgent;
	}
	
	public boolean getValidate()
	{
		return validate;
	}
	
	public void setIsValidate(boolean validate)
	{
		this.validate = validate;
	}
}
